home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MACD 5
/
MACD 5.bin
/
workbench
/
libs
/
unixlib.lha
/
unix
/
src
/
signals.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-10-21
|
5KB
|
298 lines
#include "amiga.h"
#include "timers.h"
#include "signals.h"
#include "processes.h"
void __stdargs _CXFERR(int);
/* When one of these occur, call handle_signals */
static ULONG signalsigs;
void (*_sig_handlers[NSIG]) (int);
long _sig_mask, _sig_pending;
/* These can be generated only by bsdsocket.library */
long _sigio_sig = -1, _sigurg_sig = -1;
extern void _fail(char *format,...);
extern void _message(char *format,...);
extern int (*_break_func)(void);
/* Alarm signal */
/* ------------ */
static struct timeinfo *alarm_timer;
static int check_alarm(void)
{
return alarm_timer && _timer_expired(alarm_timer);
}
/*
* Schedule a SIGALRM after secs seconds
*/
void alarm(int secs)
{
_timer_start(alarm_timer, secs, 0);
}
static void init_alarm(void)
{
if (!(alarm_timer = _alloc_timer()))
_fail("Failed to create timer");
signalsigs |= _timer_sig(alarm_timer);
}
static void cleanup_alarm(void)
{
_free_timer(alarm_timer);
}
/* SIGINT definition */
/* ----------------- */
static void init_sigint(void)
{
signalsigs |= SIGBREAKF_CTRL_C;
}
/* static void cleanup_sigint(void) { } */
static int check_sigint(ULONG sigs)
{
return (sigs & SIGBREAKF_CTRL_C) != 0;
}
/* SIGQUIT definition */
/* ------------------ */
static void init_sigquit(void)
{
signalsigs |= SIGBREAKF_CTRL_D;
}
/* static void cleanup_sigquit(void) { } */
static int check_sigquit(ULONG sigs)
{
return (sigs & SIGBREAKF_CTRL_D) != 0;
}
/* SIGCHLD definition */
/* ------------------ */
static void init_children(void)
{
_init_processes();
signalsigs |= 1L << _children_exit->mp_SigBit;
}
static void cleanup_children(void)
{
_cleanup_processes();
}
static int check_children(void)
{
struct exit_message *msg;
int change = FALSE;
while (msg = (struct exit_message *) GetMsg(_children_exit)) {
struct process *p;
if ((p = _find_pid(msg->pid)) && p->status == alive) {
change = TRUE;
p->status = exited;
p->rc = msg->rc;
}
FreeMem(msg, sizeof(struct exit_message));
}
return change;
}
/* SIGIO definition */
/* ---------------- */
static void init_sigio(void)
{
if (_sigio_sig >= 0)
signalsigs |= sigmask(_sigio_sig);
}
/* static void cleanup_sigio(void) { } */
static int check_sigio(ULONG sigs)
{
return _sigio_sig < 0 ? 0 : (sigs & sigmask(_sigio_sig)) != 0;
}
/* SIGURG definition */
/* ----------------- */
static void init_sigurg(void)
{
if (_sigurg_sig >= 0)
signalsigs |= sigmask(_sigurg_sig);
}
/* static void cleanup_sigurg(void) { } */
static int check_sigurg(ULONG sigs)
{
return _sigurg_sig < 0 ? 0 : (sigs & sigmask(_sigurg_sig)) != 0;
}
/* Signal dispatching */
/* ------------------ */
/*
* Do the action associated with signal sig if it isn't masked
* Mask it for the duration of the signal exec
*/
void _sig_dispatch(int sig)
{
void (*fn) (int);
int smask = sigmask(sig);
if (sig == SIGKILL)
__exit(0);
if (_sig_mask & smask) {
_sig_pending |= smask;
} else {
do {
_sig_pending &= ~smask;
if (sig >= 0 && sig < NSIG) {
fn = _sig_handlers[sig];
/*
* Note: SIGINT is special because onbreak() may
* override the SIG_DFL and SIG_IGN settings.
*/
if (sig == SIGINT) {
_sig_mask |= smask;
if (_break_func()) {
_message("user interrupt");
__exit(0);
}
_sig_mask &= ~smask;
} else if (fn == SIG_DFL) {
switch (sig) {
case SIGURG:
case SIGCHLD:
case SIGIO:
case SIGWINCH:
break;
case SIGQUIT:
_message("user interrupt");
default:
__exit(0);
}
} else if (fn != SIG_IGN) {
_sig_mask |= smask;
_sig_handlers[sig] (sig);
_sig_mask &= ~smask;
}
}
}
while (_sig_pending & smask); /* Signal may have been generated during
the signal handling function. */
}
}
ULONG _check_signals(ULONG extra_sigs)
{
return SetSignal(0, signalsigs | extra_sigs);
}
ULONG _wait_signals(ULONG extra_sigs)
{
return Wait(signalsigs | extra_sigs);
}
int _handle_signals(ULONG sigs)
{
int signaled = 0;
if (check_alarm()) {
signaled = 1;
_sig_dispatch(SIGALRM);
}
if (check_sigint(sigs)) {
signaled = 1;
_sig_dispatch(SIGINT);
}
if (check_sigquit(sigs)) {
signaled = 1;
_sig_dispatch(SIGQUIT);
}
if (check_sigio(sigs)) {
signaled = 1;
_sig_dispatch(SIGIO);
}
if (check_sigurg(sigs)) {
signaled = 1;
_sig_dispatch(SIGURG);
}
if (check_children()) {
signaled = 1;
_sig_dispatch(SIGCHLD);
}
return signaled;
}
/*
* Patch into SAS signal stuff so as to replace it
*/
void __stdargs _CXFERR(int code)
{
extern int _FPERR;
_FPERR = code;
_sig_dispatch(SIGFPE);
}
/*
* Checks all signals
*/
void __regargs __chkabort(void)
{
_handle_signals(_check_signals(0));
}
void __stdargs Chk_Abort(void)
{
__chkabort();
}
/* Initialisation */
/* -------------- */
void _init_signals(void)
{
int i;
for (i = 0; i < NSIG; i++)
_sig_handlers[i] = SIG_DFL;
_sig_mask = _sig_pending = 0;
signalsigs = 0;
init_sigint();
init_sigquit();
init_sigio();
init_sigurg();
init_alarm();
init_children();
}
void _cleanup_signals(void)
{
cleanup_alarm();
/* cleanup_sigquit(); */
/* cleanup_sigint(); */
/* cleanup_sigio(); */
/* cleanup_sigurg(); */
cleanup_children();
}